package cn.t.facade.device;

import cn.t.constants.CommonConstants;
import cn.t.constants.ResponseError;
import cn.t.converter.device.CargowayDTOConverter;
import cn.t.converter.order.ReplenishmentRecordDTOConverter;
import cn.t.core.exception.BizException;
import cn.t.core.facade.FacadeImpl;
import cn.t.dto.api.CustomerItemDTO;
import cn.t.dto.device.CargowayDTO;
import cn.t.dto.order.ExcelBatchOnShelfDTO;
import cn.t.enums.order.ErrorEnum;
import cn.t.model.device.CargowayDO;
import cn.t.model.device.CargowaySkuDO;
import cn.t.model.device.DeviceDO;
import cn.t.model.order.ReplenishmentRecordDO;
import cn.t.model.sku.SkuDO;
import cn.t.model.user.CustomerFirmDO;
import cn.t.service.device.CargowayService;
import cn.t.service.device.CargowaySkuService;
import cn.t.service.device.DeviceService;
import cn.t.service.order.ReplenishmentRecordService;
import cn.t.service.sku.SkuService;
import cn.t.service.user.CustomerFirmService;
import cn.t.vo.device.CargowaySkuVO;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 货道表(Cargoway)服务编排
 *
 * @author t
 * @since 2024-05-24 10:19:33
 */
@Slf4j
@Service
@AllArgsConstructor
public class CargowayFacade extends FacadeImpl<CargowayDTO, CargowayDO, CargowayDTOConverter, CargowayService> {

    private final DeviceService deviceService;
    private final CargowaySkuService cargowaySkuService;
    private final CustomerFirmService customerFirmService;
    private final SkuService skuService;
    private final ReplenishmentRecordService replenishmentRecordService;
    private final ReplenishmentRecordDTOConverter replenishmentRecordDTOConverter;

    public List<CargowayDTO> getInfoByDeviceId(Long deviceId) {
        if (deviceId == null) {
            throw new BizException(ResponseError.PARAM_NOT_FOUND, String.format(ResponseError.PARAM_NOT_FOUND.getName(), "deviceId"));
        }
        List<CargowayDO> list = service.getCargowayList(Collections.singletonList(deviceId));
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        return list.stream().map(converter::model2Dto).collect(Collectors.toList());
    }

    public void exportSkuLabel(HttpServletResponse response, Long deviceId) {
        try {
            // 设置响应头,重命名文件
            String encodeFileName= URLEncoder.encode("sku标签_"+deviceId+"_", "UTF-8");
            String newName = new String(encodeFileName.getBytes(), StandardCharsets.UTF_8) + DateTimeFormatter.ofPattern("yyyyMMddHHmm").format(LocalDateTime.now()) + ".xlsx";
            response.setContentType("application/force-download");
            response.setHeader("Content-Disposition", "attachment;filename=" + newName);

            // 获取设备所有货道sku信息
            DeviceDO deviceDO = deviceService.findById(deviceId);
            if (null == deviceDO) {
                throw new BizException(ErrorEnum.NO_DATA, ErrorEnum.NO_DATA.getMessage());
            }

            // 查询所有货道商品
            List<CargowaySkuDO> cargowayDOS = this.cargowaySkuService.getDeviceSkuList(Lists.newArrayList(deviceId));



            //循环拼接字符串
            List<String> skuLabels = new ArrayList<>();

            for (CargowaySkuDO cargowaySku : cargowayDOS) {
                StringBuilder sb = new StringBuilder();
                sb.append(cargowaySku.getSkuName()).append("\n").append("SKU ：").append(cargowaySku.getSkuCode());
                // 拼接客户物料
                skuLabels.add(sb.toString());
            }

            List<List<String>> lists = this.service.convertToExcelRows(skuLabels);

            this.service.generateExcel(lists, response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public List<ExcelBatchOnShelfDTO> checkAndGetExcelData(MultipartFile file, AnalysisEventListener<ExcelBatchOnShelfDTO> eventListener) {
        List<ExcelBatchOnShelfDTO> excelData;
        // 获取文件名
        String fileName = file.getOriginalFilename();
        // 验证文件名是否合格
        if (!StringUtils.hasText(fileName) || !fileName.matches("^.+\\.(xls|xlsx)$")) {
            throw new BizException(ErrorEnum.FILE_FORMAT_ERROR,  ErrorEnum.FILE_FORMAT_ERROR.getMessage());
        }

        try {
            excelData = EasyExcelFactory.read(file.getInputStream(), ExcelBatchOnShelfDTO.class, eventListener).sheet().headRowNumber(CommonConstants.ONE).doReadSync();
            // 过滤掉空行
            excelData = excelData.stream().filter(f -> StringUtils.hasText(f.getSkuCode())).collect(Collectors.toList());
            // 如果数据有异常所有数据都不处理
            List<ExcelBatchOnShelfDTO> errList = excelData.stream().filter(line -> !ObjectUtils.isEmpty(line.getErrLog())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(errList)) {
                String errLog = errList.stream().map(ExcelBatchOnShelfDTO::getErrLog).collect(Collectors.joining(";"));
                throw new BizException(ErrorEnum.FILE_PARSE_ERROR, errLog);
            }
        } catch (Exception e) {
            log.error("货道批量上架导入文件解析失败 {}", e.getMessage());
            throw new BizException(ErrorEnum.FILE_PARSE_ERROR, ErrorEnum.FILE_PARSE_ERROR.getMessage());
        }

        if (CollectionUtils.isEmpty(excelData)){
            throw new BizException(ErrorEnum.NO_DATA, ErrorEnum.NO_DATA.getMessage());
        }
        return excelData;
    }

    public String batchOnShelf(List<ExcelBatchOnShelfDTO> list, Long deviceId) {

        //校验货道号是否有重复信息
        Map<Integer, ExcelBatchOnShelfDTO> importCargowayDtoMap = list.stream().collect(Collectors.toMap(ExcelBatchOnShelfDTO::getCargowayNo, Function.identity(), (o, n) -> o));
        if (importCargowayDtoMap.size() != list.size()) {
            throw new BizException(ErrorEnum.CARGOWAY_CODE_RE, ErrorEnum.CARGOWAY_CODE_RE.getMessage());
        }
        //获取sku信息为map
        List<String> skuCodes = list.stream().map(ExcelBatchOnShelfDTO::getSkuCode).distinct().collect(Collectors.toList());

        List<SkuDO> skuList = this.skuService.findModelList(skuCodes);
        //检验sku 是否存在
        Map<String, SkuDO> skuMap =skuList.stream().collect(Collectors.toMap(SkuDO::getSkuCode, Function.identity(), (o, n) -> o));
        List<String> notExistsSku = skuCodes.stream().filter(skuCode -> Objects.isNull(skuMap.get(skuCode))).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(notExistsSku)) {
            throw new BizException(ErrorEnum.SKU_NOT_FOUND, String.format(ErrorEnum.SKU_NOT_FOUND.getMessage(), JSON.toJSON(notExistsSku)));
        }
        //检验sku 是否存在
        List<DeviceDO> devices = deviceService.getDevicesByMasterDeviceId(deviceId);
        if (CollectionUtils.isEmpty(devices)) {
            throw new BizException(ErrorEnum.DEVICE_NOT_FOUND, String.format(ErrorEnum.DEVICE_NOT_FOUND.getMessage(), deviceId));
        }
        //获取货道信息
        List<Long> deviceIds = devices.stream().map(DeviceDO::getId).collect(Collectors.toList());
        List<CargowayDO> cargowayDOS = this.service.getCargowayList(deviceIds);
        //获取商品与货道绑定信息
        List<CargowaySkuDO> cargowaySkuDOS = cargowaySkuService.getDeviceSkuList(deviceIds);
        Map<Long, CargowaySkuDO> cargowayGoodsMap = cargowaySkuDOS.stream().collect(Collectors.toMap(CargowaySkuDO::getCargowayId, Function.identity()));
        //转map ,副柜货道号不可能重复
        Map<Integer, CargowayDO> cargowayMap = cargowayDOS.stream().collect(Collectors.toMap(CargowayDO::getCargowayNo, Function.identity()));
        //收集上架商品
        ArrayList<CargowaySkuDO> onShelfGoods = new ArrayList<>();
        ArrayList<CargowayDO> onShelfCargoWayList = new ArrayList<>();
        //收集下架商品
        ArrayList<CargowaySkuDO> offShelfGoods = new ArrayList<>();

        //收集需要修改的商品数据
        Map<String, SkuDO> updateGoodsMap = new HashMap<>();

        List<ReplenishmentRecordDO> saveRecords = new ArrayList<>();
        for (Map.Entry<Integer, ExcelBatchOnShelfDTO> integerImportCargowayDtoEntry : importCargowayDtoMap.entrySet()) {
            Integer cargowayNo = integerImportCargowayDtoEntry.getKey();
            //校验货道号是否在设备中存在
            CargowayDO cargoway = cargowayMap.get(cargowayNo);
            if (Objects.isNull(cargoway)) {
                throw new BizException(ErrorEnum.CARGOWAY_CODE_NOT_FOUND, String.format(ErrorEnum.CARGOWAY_CODE_NOT_FOUND.getMessage(), cargowayNo));
            }
            ExcelBatchOnShelfDTO batchOnShelfDTO = integerImportCargowayDtoEntry.getValue();
            Integer isEdit = batchOnShelfDTO.getIsEdit();
            CargowaySkuDO cargowaySku = cargowayGoodsMap.get(cargoway.getId());
            SkuDO skuDO = skuMap.get(batchOnShelfDTO.getSkuCode());
            //组装上架 或者下架的数据,或者已经上架过
            if (CommonConstants.ONE.equals(isEdit)) {
                boolean isUpdate = ObjectUtils.isEmpty(batchOnShelfDTO.getWeight()) ? Boolean.FALSE : Boolean.TRUE;
                if (isUpdate) {
                    updateGoodsMap.put(skuDO.getSkuCode(), skuDO);
                    skuDO.setWeight(BigDecimal.valueOf(batchOnShelfDTO.getWeight()));
                }
                cargowaySku = this.converter.createUpdateCargowayGoods(batchOnShelfDTO, cargowaySku, cargoway, skuDO);
                //修改上架或者重复上架商品
                onShelfGoods.add(cargowaySku);
                //修改上架货道信息
                onShelfCargoWayList.add(cargoway);

                // 如果库存大于0，添加库存调整记录
                if (batchOnShelfDTO.getInventory() != null && batchOnShelfDTO.getInventory() > 0) {
                    ReplenishmentRecordDO replenishmentRecordDO = this.replenishmentRecordDTOConverter.req2ReplenishmentRecord(cargoway, batchOnShelfDTO.getInventory(), skuDO.getSkuCode(), skuDO.getSkuName());
                    saveRecords.add(replenishmentRecordDO);
                }

            } else if (CommonConstants.ZERO.equals(isEdit)) {
                if (Objects.isNull(cargowaySku)) {
                    throw new BizException(ErrorEnum.OFF_NOT_FOUND, String.format(ErrorEnum.OFF_NOT_FOUND.getMessage(), cargowayNo));
                }
                //收集下架商品
                offShelfGoods.add(cargowaySku);
            }
            if (!CollectionUtils.isEmpty(saveRecords)) {
                replenishmentRecordService.addBatch(saveRecords);
            }
        }
        StringBuilder sb = new StringBuilder();
        if (!CollectionUtils.isEmpty(onShelfGoods)) {
            sb.append("上架商品数量：").append(onShelfGoods.size());
        }
        if (!CollectionUtils.isEmpty(offShelfGoods)) {
            sb.append(" 下架商品数量：").append(offShelfGoods.size());
        }
        if (updateGoodsMap.size() > 0) {
            sb.append(" 修改的商品信息sku数量：").append(updateGoodsMap.size());
        }
        if (sb.length() == 0) {
            return "上架商品数量：0 下架商品数量：0 修改的商品信息sku：0";
        }
        log.info(sb.toString());
        //数据处理
        cargowaySkuService.createCargowayGoods(onShelfGoods, onShelfCargoWayList, offShelfGoods, updateGoodsMap);
        return sb.toString();
    }

    public List<CargowaySkuVO> list(Long deviceId, String skuName, String skuCode, Boolean isAlert) {

        // 查询所有主副柜信息
        List<DeviceDO> devices = this.deviceService.getDevicesByMasterDeviceId(deviceId);
        List<Long> deviceIds = devices.stream().map(DeviceDO::getId).collect(Collectors.toList());

        // 设备货道
        List<CargowayDO> cargowayDOS = this.service.getCargowayList(deviceIds);

        // 设备商品
        List<CargowaySkuDO> cargowaySkuDOS = cargowaySkuService.getDeviceSkuList(deviceIds);

        //一个货道可以放多个商品
        Map<Long, List<CargowaySkuDO>> cargowaySkuMap = cargowaySkuDOS.stream().collect(Collectors.groupingBy(CargowaySkuDO::getCargowayId));

        List<CargowaySkuVO> cargowaySkuVOS = new ArrayList<>();
        for (CargowayDO cargoway:cargowayDOS) {
            List<CargowaySkuDO> cargowaySkuList= cargowaySkuMap.get(cargoway.getId());
            if (CollectionUtils.isEmpty(cargowaySkuList)) {
                cargowaySkuVOS.add(this.converter.data2CargowaySkuVo(cargoway, null));
            } else {
                for (CargowaySkuDO cargowaySku:cargowaySkuList) {
                    cargowaySkuVOS.add(this.converter.data2CargowaySkuVo(cargoway, cargowaySku));
                }
            }
        }

        // 过滤
        if (StringUtils.hasText(skuName)) {
            cargowaySkuVOS = cargowaySkuVOS.stream().filter(f -> f.getSkuName().contains(skuName)).collect(Collectors.toList());
        }
        if (StringUtils.hasText(skuCode)) {
            cargowaySkuVOS = cargowaySkuVOS.stream().filter(f -> skuCode.equals(f.getSkuCode())).collect(Collectors.toList());
        }
        if (Boolean.TRUE.equals(isAlert)) {
            cargowaySkuVOS = cargowaySkuVOS.stream().filter(f -> !CommonConstants.ZERO.equals(f.getAlarmLimit())).collect(Collectors.toList());
        }
        if (Boolean.FALSE.equals(isAlert)) {
            cargowaySkuVOS = cargowaySkuVOS.stream().filter(f -> f.getAlarmLimit() > CommonConstants.ZERO).collect(Collectors.toList());
        }

        // 排序
        cargowaySkuVOS.sort(Comparator.comparing(CargowaySkuVO::getCargowayNo));
        return cargowaySkuVOS;
    }

    public boolean removeById(Long id) {
        List<CargowaySkuDO> cargowaySkuDOS = cargowaySkuService.getCargowaySku(null, id);
        if (!CollectionUtils.isEmpty(cargowaySkuDOS)) {
            throw new BizException(ErrorEnum.BUSINESS_ERROR, "请先下架商品再删除货道");
        }
        return this.service.removeById(id);
    }
}

